﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Tools;

namespace Pixysoft.Framework.Sockets.Core
{
    /// <summary>
    /// socket服务器性能检测器
    /// </summary>
    class GlobalPerformanceAnalyzer : IGlobalPerformance
    {
        DateTime createDate = GlobalTimer.Instance.GetGlobalTime();

        DateTime currentRequestTime = DateTime.MinValue;
        DateTime formerRequestTime = DateTime.MinValue;

        DateTime currentResponseTime = DateTime.MinValue;
        DateTime formerResponseTime = DateTime.MinValue;

        // session analyzer

        long createSessionCounter;
        long removeSessionCounter;
        long errorSessionCounter;

        // request analyzer

        long requestCounter;
        long responseCounter;
        long processCounter;

        double requestInterval = -1;// 请求频率
        double responseInterval = -1;// 回复频率
        double processInterval = -1;// 处理频率

        private static volatile GlobalPerformanceAnalyzer instance;

        private static object syncRoot = new Object();

        public static GlobalPerformanceAnalyzer Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            instance = new GlobalPerformanceAnalyzer();
                        }
                    }
                }
                return instance;
            }
        }

        public void CreateSession()
        {
            lock (syncRoot)
            {
                this.createSessionCounter++;
            }
        }

        public void RemoveSession()
        {
            lock (syncRoot)
            {
                this.removeSessionCounter--;
            }
        }

        public void ErrorSession()
        {
            lock (syncRoot)
            {
                this.errorSessionCounter++;
            }
        }

        public double OnRequestArrived()
        {
            lock (syncRoot)
            {
                DateTime requestTime = GlobalTimer.Instance.GetGlobalTime();

                if (this.currentRequestTime == DateTime.MinValue
                        || this.formerRequestTime == DateTime.MinValue)
                {
                    this.formerRequestTime = requestTime;

                    this.currentRequestTime = requestTime;

                    requestCounter++;

                    return -1;
                }

                TimeSpan reqSpan = requestTime - currentRequestTime;

                long interval = reqSpan.Milliseconds;

                formerRequestTime = currentRequestTime;

                currentRequestTime = requestTime;

                if (this.requestInterval < 0)
                {
                    this.requestInterval = interval;
                }
                else
                {
                    double nRequestInterval = (this.requestInterval * this.requestCounter + interval) / (this.requestCounter + 1);

                    this.requestInterval = nRequestInterval;
                }

                this.requestCounter++;

                return this.requestInterval;
            }
        }

        public double OnResponseSent()
        {
            lock (syncRoot)
            {
                DateTime responseTime = GlobalTimer.Instance.GetGlobalTime();

                if (this.currentResponseTime == DateTime.MinValue
                        || this.formerResponseTime == DateTime.MinValue)
                {
                    this.formerResponseTime = responseTime;

                    this.currentResponseTime = responseTime;

                    responseCounter++;

                    return -1;
                }

                TimeSpan reqSpan = responseTime - currentResponseTime;

                long interval = reqSpan.Milliseconds;

                formerResponseTime = currentResponseTime;

                currentResponseTime = responseTime;

                if (this.responseInterval < 0)
                {
                    this.responseInterval = interval;
                }
                else
                {
                    double nResponseInterval = (this.responseInterval * this.responseCounter + interval) / (this.responseCounter + 1);

                    this.responseInterval = nResponseInterval;
                }

                this.responseCounter++;

                return this.responseInterval;
            }
        }

        public double OnProcessEnd(long interval)
        {
            lock (syncRoot)
            {
                this.processCounter++;

                if (this.processInterval < 0)
                {
                    this.processInterval = interval;
                }
                else
                {
                    this.processInterval = (this.processInterval * this.processCounter + interval) / (this.processCounter + 1);
                }

                return this.processInterval;
            }
        }

        public DateTime GetCreateDate()
        {
            return createDate;
        }


        public long GetCreateSessionCounter()
        {
            return createSessionCounter;
        }


        public long GetRemoveSessionCounter()
        {
            return removeSessionCounter;
        }


        public long GetRequestCounter()
        {
            return requestCounter;
        }


        public long GetResponseCounter()
        {
            return responseCounter;
        }


        public double GetRequestInterval()
        {
            return requestInterval;
        }


        public long GetErrorSessionCounter()
        {
            return errorSessionCounter;
        }


        public double GetResponseInterval()
        {
            return responseInterval;
        }


        public double GetProcessInterval()
        {
            return processInterval;
        }


        public long GetProcessCounter()
        {
            return processCounter;
        }
    }
}
